-include common.mk

# os source code path
-include $(BOARDPATH)/meta/arch/config.mk
-include $(BOARDPATH)/meta/portable/config.mk
-include $(BOARDPATH)/meta/system/config.mk
-include $(BOARDPATH)/meta/utils/config.mk
-include $(BOARDPATH)/meta/task/config.mk
-include $(BOARDPATH)/meta/driver/config.mk
-include $(BOARDPATH)/meta/itc/config.mk
-include $(BOARDPATH)/meta/memory/config.mk
-include $(BOARDPATH)/meta/shell/config.mk
-include $(BOARDPATH)/meta/kprocess/config.mk

#
# APP input arguments:
#	$(CC)				- C compiler
#	$(AS)				- ASM compiler
#	$(LD)				- C linker
#	$(KAPP_PROJPATH)	- The path of kernel application for compiler
#	$(KAPP_SRCDIRS)		- The full path of source files (.c .s .S)
#	$(KAPP_INCDIRS)		- The full path of header files (.h)
#	$(KAPP_CFLAGS)		- C compiler flags
#	$(KAPP_SFLAGS)		- ASM compiler flags
#	$(KAPP_LFLAGS)		- C linker flags
#	$(BOARDPATH)		- The board path
# Optional input arguments:
#	$(KAPP_IGNORES)		- The list of ignore files
#	$(KAPP_TARGET)		- The final object file name, exclude path
#	$(V)				- Silent of not (pass by commandline)
#

# -------- parameters checkout

ifeq ($(CC),)
$(error CC should not be null)
endif
ifeq ($(LD),)
$(error LD should not be null)
endif
ifeq ($(AS),)
$(error AS should not be null)
endif
ifeq ($(KAPP_PROJPATH),)
$(error KAPP_PROJPATH should not be null)
endif
ifeq ($(BOARDPATH),)
$(error BOARDPATH should not be null)
endif

# -------- verbose contorl, `make V=1` to show the detail of compile

# the absolute path of matrix
ROOTPATH		:= $(abspath ./)

# note: must use the `=` instead of `:=` because of $</$@
SILENT			 = @
CMSG			 = @echo BUILD: $(subst $(ROOTPATH)/,,$<)
LMSG			 = @echo Generated: $(subst $(ROOTPATH)/,,$@)
ifeq ("$(origin V)", "command line")
	ifeq ($(V),1)
SILENT	 		 =
CMSG	 		 =
	endif
endif

# -------- makefile's arguments

KAPP_TARGET		?= kapp

# -------- generate target files

# check whether the board folder contain matrix
ISCONTAIN_MX	:= $(and $(filter $(KAPP_PROJPATH)/%,$(ROOTPATH)),$(if $(filter $(KAPP_PROJPATH),$(ROOTPATH)),,yes))

# get the source files
SRCFILES		:= $(foreach dir,$(KAPP_SRCDIRS),$(wildcard $(dir)/*.c))
SRCFILES		+= $(foreach dir,$(KAPP_SRCDIRS),$(wildcard $(dir)/*.cpp))
SRCFILES		+= $(foreach dir,$(KAPP_SRCDIRS),$(wildcard $(dir)/*.s))
SRCFILES		+= $(foreach dir,$(KAPP_SRCDIRS),$(wildcard $(dir)/*.S))

# remove ignore files
KAPP_IGNORES	:= $(wildcard $(KAPP_IGNORES))
SRCFILES		:= $(filter-out $(KAPP_IGNORES),$(SRCFILES))

ifeq ($(ISCONTAIN_MX),yes)
# generate objects in `kprocess/kapp` (must be first)
OBJS			:= $(patsubst $(ROOTPATH)/kprocess/kapp/%.c,$(KAPP_PROJPATH)/build/kapp/%.o,$(SRCFILES))
OBJS			:= $(patsubst $(ROOTPATH)/kprocess/kapp/%.cpp,$(KAPP_PROJPATH)/build/kapp/%.o,$(OBJS))
OBJS			:= $(patsubst $(ROOTPATH)/kprocess/kapp/%.s,$(KAPP_PROJPATH)/build/kapp/%.o,$(OBJS))
OBJS			:= $(patsubst $(ROOTPATH)/kprocess/kapp/%.S,$(KAPP_PROJPATH)/build/kapp/%.o,$(OBJS))
# generate objects in `app`
OBJS			:= $(patsubst $(KAPP_PROJPATH)/%.c,$(KAPP_PROJPATH)/build/app/%.o,$(OBJS))
OBJS			:= $(patsubst $(KAPP_PROJPATH)/%.cpp,$(KAPP_PROJPATH)/build/app/%.o,$(OBJS))
OBJS			:= $(patsubst $(KAPP_PROJPATH)/%.s,$(KAPP_PROJPATH)/build/app/%.o,$(OBJS))
OBJS			:= $(patsubst $(KAPP_PROJPATH)/%.S,$(KAPP_PROJPATH)/build/app/%.o,$(OBJS))
else
# generate objects in `app` (must be first)
OBJS			:= $(patsubst $(KAPP_PROJPATH)/%.c,$(KAPP_PROJPATH)/build/app/%.o,$(SRCFILES))
OBJS			:= $(patsubst $(KAPP_PROJPATH)/%.cpp,$(KAPP_PROJPATH)/build/app/%.o,$(OBJS))
OBJS			:= $(patsubst $(KAPP_PROJPATH)/%.s,$(KAPP_PROJPATH)/build/app/%.o,$(OBJS))
OBJS			:= $(patsubst $(KAPP_PROJPATH)/%.S,$(KAPP_PROJPATH)/build/app/%.o,$(OBJS))
# generate objects in `kprocess/kapp`
OBJS			:= $(patsubst $(ROOTPATH)/kprocess/kapp/%.c,$(KAPP_PROJPATH)/build/kapp/%.o,$(OBJS))
OBJS			:= $(patsubst $(ROOTPATH)/kprocess/kapp/%.cpp,$(KAPP_PROJPATH)/build/kapp/%.o,$(OBJS))
OBJS			:= $(patsubst $(ROOTPATH)/kprocess/kapp/%.s,$(KAPP_PROJPATH)/build/kapp/%.o,$(OBJS))
OBJS			:= $(patsubst $(ROOTPATH)/kprocess/kapp/%.S,$(KAPP_PROJPATH)/build/kapp/%.o,$(OBJS))
endif

# -------- include path

# add kernel's path (use relative path)
I				:= $(subst $(ROOTPATH)/,,$(INCDIRS))
# add app's path (if the app project under the kernel folder, it will be convert to relative path)
I				+= $(subst $(ROOTPATH)/,,$(KAPP_INCDIRS))
# add `-I`
I				:= $(foreach dir,$(I),-I$(dir))

# -------- rules

# target file
$(KAPP_PROJPATH)/build/$(KAPP_TARGET).elf : $(OBJS)
	$(SILENT) $(LD) $(KAPP_LFLAGS) -o $@ $^
	$(LMSG)

# app object files
$(KAPP_PROJPATH)/build/app/%.o : $(KAPP_PROJPATH)/%.c
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(CC) $(KAPP_CFLAGS) $(I) -o $@ $<
$(KAPP_PROJPATH)/build/app/%.o : $(KAPP_PROJPATH)/%.cpp
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(CC) $(KAPP_CFLAGS) $(I) -o $@ $<
$(KAPP_PROJPATH)/build/app/%.o : $(KAPP_PROJPATH)/%.s
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(AS) $(KAPP_SFLAGS) $(I) -o $@ $<
$(KAPP_PROJPATH)/build/app/%.o : $(KAPP_PROJPATH)/%.S
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(AS) $(KAPP_SFLAGS) $(I) -o $@ $<

# kernel object file (kprocess/kapp)
$(KAPP_PROJPATH)/build/kapp/%.o : kprocess/kapp/%.c
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(CC) $(KAPP_CFLAGS) $(I) -o $@ $<
$(KAPP_PROJPATH)/build/kapp/%.o : kprocess/kapp/%.cpp
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(CC) $(KAPP_CFLAGS) $(I) -o $@ $<
$(KAPP_PROJPATH)/build/kapp/%.o : kprocess/kapp/%.s
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(AS) $(KAPP_SFLAGS) $(I) -o $@ $<
$(KAPP_PROJPATH)/build/kapp/%.o : kprocess/kapp/%.S
	$(CMSG)
	$(SILENT) mkdir -p $(@D)
	$(SILENT) $(AS) $(KAPP_SFLAGS) $(I) -o $@ $<

# -------- pseudo target
.PHONY: clean

clean:
	@rm -rf $(KAPP_PROJPATH)/build/*
